package org.dromara.tearoom.service.impl;

import cn.hutool.http.HttpStatus;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.BeanUtils;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.tearoom.domain.TerRechargeRules;
import org.dromara.tearoom.domain.bo.TerTransactionsBo;
import org.dromara.tearoom.domain.vo.*;
import org.dromara.tearoom.mapper.TerRechargeRulesMapper;
import org.dromara.tearoom.service.ITerTransactionsService;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;
import org.dromara.tearoom.domain.bo.TerAccountsBo;
import org.dromara.tearoom.domain.TerAccounts;
import org.dromara.tearoom.mapper.TerAccountsMapper;
import org.dromara.tearoom.service.ITerAccountsService;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Collection;

/**
 * 账户Service业务层处理
 *
 * @author xch
 * @date 2025-05-07
 */
@RequiredArgsConstructor
@EnableConfigurationProperties(WxPayProperties.class)
@Service
public class TerAccountsServiceImpl implements ITerAccountsService {
    private final TerRechargeRulesMapper terRechargeRulesMapper;
    private final TerAccountsMapper baseMapper;
    private final ITerTransactionsService transactionsService;

    private final PayService payService;
    private final WxPayProperties wxPayProperties;
    private final TerTransactionsServiceImpl terTransactionsServiceImpl;

    /**
     * 查询账户
     *
     * @param type 主键
     * @return 账户
     */
    @Override
    public TerAccountsVo queryById(Integer type){
        TerAccounts accounts = baseMapper.selectOne(new QueryWrapper<TerAccounts>().eq("member_id", LoginHelper.getAppLoginUser().getId()));
        if(accounts == null){  throw new ServiceException("账户不存在！");}
        if(type==0){
          return offsetAmount(accounts,"账户充值");
        }
        TerAccountsVo tav=BeanUtils.toBean(accounts, TerAccountsVo.class);
        tav.setTotalAmount(accounts.getBalance()+accounts.getGiftAmount());
        return tav;
    }
    @Override
    public TerAccountsVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }
    /**
     * 分页查询账户列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 账户分页列表
     */
    @Override
    public TableDataInfo<TerAccountsVo> queryPageList(TerAccountsBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<TerAccounts> lqw = buildQueryWrapper(bo);
        Page<TerAccountsVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的账户列表
     *
     * @param bo 查询条件
     * @return 账户列表
     */
    @Override
    public List<TerAccountsVo> queryList(TerAccountsBo bo) {
        LambdaQueryWrapper<TerAccounts> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<TerAccounts> buildQueryWrapper(TerAccountsBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<TerAccounts> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(TerAccounts::getId);
        lqw.eq(bo.getMemberId() != null, TerAccounts::getMemberId, bo.getMemberId());
        lqw.eq(bo.getBalance() != null, TerAccounts::getBalance, bo.getBalance());
        lqw.eq(bo.getIntegral() != null, TerAccounts::getIntegral, bo.getIntegral());
        lqw.eq(bo.getType() != null, TerAccounts::getType, bo.getType());
        return lqw;
    }

    /**
     * 新增账户
     *
     * @param bo 账户
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(TerAccountsBo bo) {
        bo.setCreateTime(new Date());
        TerAccounts add = MapstructUtils.convert(bo, TerAccounts.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改账户
     *
     * @param bo 账户
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(TerAccountsBo bo) {
        TerAccounts update = MapstructUtils.convert(bo, TerAccounts.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(TerAccounts entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 校验并批量删除账户信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    @Transactional
    public TerTransactionsBo recharge(TerAccountsBo bo){
        TerAccounts account = baseMapper.selectOne(new QueryWrapper<TerAccounts>().eq("member_id", LoginHelper.getAppLoginUser().getId()));
        if(account.getType()==0){
            throw new ServiceException("账户已冻结!");
        }
        //查询规则匹配
        Integer bonus=0;
        TerRechargeRules rule = terRechargeRulesMapper.selectMatchedRule(bo.getBalance());
        if(rule!=null) {
            bonus = switch (rule.getRewardType()) {
                case 0 -> rule.getRewardValue();
                case 1 -> bo.getBalance()* rule.getRewardValue();
                default -> 0;
            };
        }

        int updated = baseMapper.updateBalance(
                account.getId(),
                bo.getBalance(),
                bonus,
                account.getVersion());
        if(updated == 0){
            throw new ServiceException("更新异常!");
        }

        TerTransactionsBo transaction = new TerTransactionsBo();
        transaction.setMemberId(account.getMemberId());
        transaction.setRemark("账户充值");
        transaction.setAccountId(account.getId());
        transaction.setAmount(bo.getBalance()+bonus);
        transaction.setBalanceBefore(account.getBalance());
        transaction.setBalanceAfter(account.getBalance()+bo.getBalance());
        transaction.setGiftBefore(account.getGiftAmount());
        transaction.setGiftAfter(account.getGiftAmount()+bonus);
        transaction.setCreateTime(LocalDateTime.now());
        transactionsService.insertByBo(transaction);
        return transaction;
    }

    @Override
    @Transactional
    public int deductBalance(Integer amount) {
        //查询账户信息
        TerAccounts account = baseMapper.selectOne(new QueryWrapper<TerAccounts>().eq("member_id", LoginHelper.getAppLoginUser().getId()));
        int num =0;
        if(account.getType()==0){
            throw new ServiceException("账户已冻结!");
        }
        Integer totaol = account.getBalance()+account.getGiftAmount();
        int blanceDec = 0;
        int giftDec = 0;
        if(account.getBalance()-amount<0&&totaol-amount<0){
            num =amount-totaol;
            blanceDec = account.getBalance();
            giftDec = account.getGiftAmount();
            amount = account.getBalance()+account.getGiftAmount();
        }else if(account.getBalance()-amount<0&&totaol-amount>0){
            blanceDec = account.getBalance();
            giftDec = amount - account.getBalance();
            amount = account.getBalance();
        }else{
            blanceDec = amount;
        }
        int updated = baseMapper.updateDecBalance(
                account.getId(),
                blanceDec,
                giftDec,
                account.getVersion());
        if (updated == 0) {
            throw new ServiceException("更新异常!");
        }
        TerTransactionsBo transaction = new TerTransactionsBo();
        transaction.setMemberId(account.getMemberId());
        transaction.setRemark("账户扣减");
        transaction.setAccountId(account.getId());
        transaction.setAmount(amount);
        transaction.setBalanceBefore(account.getBalance());
        transaction.setBalanceAfter(num>0?0:account.getBalance()-blanceDec);
        transaction.setGiftBefore(account.getGiftAmount());
        transaction.setGiftAfter(num>0?0:account.getGiftAmount()-giftDec);
        transaction.setCreateTime(LocalDateTime.now());
        transactionsService.insertByBo(transaction);


        return num;
    }
    @Override
    public WxSignParam payAccount(TerAccountsBo bo){
        WxPayVo vo = new WxPayVo();
        if(StringUtils.isBlank(bo.getOrderId())){
            //账户充值
            TerTransactionsBo trb= recharge(bo);
            vo.setOutTradeNo("TEH-"+trb.getId()+"3pg");
        }else{
            vo.setOutTradeNo(bo.getOrderId());
        }
        WxSignParam wsp = new WxSignParam();
        //微信JSAPI支付
        vo.setOpenId(bo.getOpenId());
        vo.setBody(wxPayProperties.getBody());
        vo.setNotifyUrl(wxPayProperties.getNotifyUrl());
        vo.setTotalFee(bo.getBalance());
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String formattedTime = now.format(formatter);
        vo.setTimeStart(formattedTime);
        vo.setTimeExpire(now.plusMinutes(10).format(formatter));
        Object parm =  payService.transactions(vo,"JSAPI");
        if(null!=parm){
            Map<String, Object> params = (Map)parm;
            wsp.setCode(HttpStatus.HTTP_OK);
            wsp.setMsg("成功签约");
            wsp.setPaySign(params.get("paySign").toString());
            wsp.setAppId(params.get("appId").toString());
            wsp.setNonceStr(params.get("nonceStr").toString());
            wsp.setPackageStr(params.get("package").toString());
            wsp.setTimestamp(params.get("timeStamp").toString());
            wsp.setSignType(params.get("signType").toString());
        }else{
            throw new ServiceException("支付失败");
        }

        return wsp;
    }
    @Transactional
    public TerAccountsVo offsetAmount(TerAccounts account,String remark){
        TerTransactionsBo trb = new TerTransactionsBo();
        trb.setAccountId(account.getId());
        trb.setRemark(remark);
        List<TerTransactionsVo> list=transactionsService.queryList(trb);
        if(list==null||list.size()==0)throw new ServiceException("流水查询无记录");
        trb.setMemberId(account.getMemberId());
        trb.setRemark("账户冲正");
        trb.setAccountId(account.getId());
        trb.setAmount(list.get(0).getAmount());
        trb.setBalanceBefore(list.get(0).getBalanceAfter());
        trb.setBalanceAfter(list.get(0).getBalanceBefore());
        trb.setGiftBefore(list.get(0).getGiftAfter());
        trb.setGiftAfter(list.get(0).getGiftBefore());
        trb.setCreateTime(LocalDateTime.now());

        int updated = baseMapper.updateOffsetAmount(
                account.getId(),
                list.get(0).getBalanceBefore(),
                list.get(0).getGiftBefore(),                account.getVersion());
        if (updated == 0) {
            trb.setRemark("冲正失败");
            transactionsService.insertByBo(trb);
            updateType(account.getId(),0);
            throw new ServiceException("账户异常, 请等待!");
        }
        transactionsService.insertByBo(trb);
        TerAccountsVo tav= baseMapper.selectVoById(account.getId());
        tav.setTotalAmount(tav.getBalance()+tav.getGiftAmount());
      return tav;
    }
    //指定冻结账户解冻
    @Override
    public int unfrozen(TerAccountsBo bo){
        TerAccounts account = baseMapper.selectOne(new QueryWrapper<TerAccounts>().eq("id", bo.getId()));
        if(batchOffset(account,"冲正失败")>0){
           return  updateType(account.getId(),1);
        };
        return 0;
    }

    //批量解冻
    @Override
    public void batchUnfrozen(){
        List<TerAccounts> accountList = baseMapper.selectList(new QueryWrapper<TerAccounts>().eq("type", 0));
        accountList.forEach(account -> {
          if(batchOffset(account,"冲正失败")>0){
              updateType(account.getId(),1);
          };
        });
    }


    public int updateType(Long id,Integer type){
        TerAccounts accountExp = new TerAccounts();
        accountExp.setId(id);
        accountExp.setType(type);
       return baseMapper.updateById(accountExp);
    }

    //批量冲正
    public int batchOffset(TerAccounts account,String remark){
        TerTransactionsBo trb = new TerTransactionsBo();
        trb.setAccountId(account.getId());
        trb.setRemark(remark);
        List<TerTransactionsVo> list=transactionsService.queryList(trb);
        if(list==null||list.size()==0)throw new ServiceException("流水查询无记录");
        trb.setMemberId(account.getMemberId());
        trb.setRemark("账户解冻");
        trb.setAmount(list.get(0).getAmount());
        trb.setBalanceBefore(list.get(0).getBalanceAfter());
        trb.setBalanceAfter(list.get(0).getBalanceBefore());
        trb.setGiftBefore(list.get(0).getGiftAfter());
        trb.setGiftAfter(list.get(0).getGiftBefore());
        trb.setCreateTime(LocalDateTime.now());

        TerAccounts accountExp = new TerAccounts();
        accountExp.setId(account.getId());
        accountExp.setBalance(list.get(0).getBalanceBefore());
        accountExp.setGiftAmount(list.get(0).getGiftBefore());
        int updated = baseMapper.updateById(accountExp);
        if (updated == 0) {
            trb.setRemark("解冻失败");
            transactionsService.insertByBo(trb);
            throw new ServiceException("账户异常, 请等待!");
        }
        transactionsService.insertByBo(trb);
        return updated;
    }
    @Override
    public int queryBalance(String start, String end){
        return terTransactionsServiceImpl.queryBalance(start,end);
    }

    @Override
    public String balanceRefund(String useId) {
        //查询账户信息
        TerAccounts account = baseMapper.selectOne(new QueryWrapper<TerAccounts>().eq("member_id", useId));
        TerTransactionsBo trb = new TerTransactionsBo();
        trb.setAccountId(account.getId());
        trb.setRemark("账户扣减");
        List<TerTransactionsVo> list=transactionsService.queryList(trb);
        if(list==null||list.size()==0)throw new ServiceException("流水查询无记录");
        trb.setMemberId(account.getMemberId());
        trb.setRemark("账户退款");
        trb.setAmount(list.get(0).getAmount());
        trb.setBalanceBefore(list.get(0).getBalanceAfter());
        trb.setBalanceAfter(list.get(0).getBalanceBefore());
        trb.setGiftBefore(list.get(0).getGiftAfter());
        trb.setGiftAfter(list.get(0).getGiftBefore());
        trb.setCreateTime(LocalDateTime.now());

        int updated = baseMapper.updateOffsetAmount(
                account.getId(),
                list.get(0).getBalanceBefore(),
                list.get(0).getGiftBefore(),                account.getVersion());
        if (updated == 0) {
            trb.setRemark("退款失败");
            transactionsService.insertByBo(trb);
            updateType(account.getId(),0);
            throw new ServiceException("账户异常, 请等待!");
        }
        transactionsService.insertByBo(trb);
        return "TEH-"+trb.getId()+"3pg";
    }
}
